package custom.cards;

import java.util.ArrayList;
import java.util.Collections;
import java.util.Date;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;

import com.google.android.gcm.server.Message;
import com.google.android.gcm.server.Result;
import com.google.android.gcm.server.Sender;


/**
 * @author Rich
 *
 * Generic CardGame class that will allow a game to be played
 *
 */
public final class CardGame
{

	/**
	 * List of player IDs for all players involved in the game
	 */
	public ArrayList<String> players = new ArrayList<String>();
	/**
	 * Currently active players in the game (players who have not lost yet)
	 */
	public ArrayList<String> activePlayers = new ArrayList<String>();
	/**
	 * Players who have currently been eliminated from the game
	 */
	public ArrayList<String> lostPlayers = new ArrayList<String>();

	
	/**
	 * Hashmap to keep track of which player has which cards
	 */
	public HashMap<String,Queue<Card>> playerCards = new HashMap<String, Queue<Card>>();
	
	/**
	 * Hashmap to keep track of player IDs and their display names
	 */
	public HashMap<String,String> nameMap = new HashMap<String, String>();
	
	/**
	 * String version name of the type of game (See Above)
	 */
	public String Name = "None";
	/**
	 * DateTime object of the last player move in this game. TODO: Implement
	 */
	public Date lastMove = new Date();
	/**
	 * The API needed to talk to the Google Notification server
	 */
	private final String APIKEY = "AIzaSyCwRUqkulXB55TLVf6vfSTuMR9llYF5VKI";
	/**
	 * Default sender object for communications to the Notification server
	 */
	public Sender sender = new Sender(APIKEY);
	/**
	 * Default message object if one is not defined
	 */
	public Message message = new Message.Builder()
			.addData("ResponseType", "OK").addData("Message", "No Data")
			.build();
	/**
	 * True if the current game has a declared winner or is ended by rule; false otherwise
	 */
	public boolean GameFinished = false;
	/**
	 * True if the game has begun (ie had enough players to start)
	 */
	public boolean GameStarted = false;

	/**
	 * Name of the game Host
	 */
	public String HostName = null;
	
	/**
	 * Default ArrayList of Player cards for your card game
	 */
	public ArrayList<Card> cards = new ArrayList<Card>();;
	
	public ArrayList<String> cardLock = new ArrayList<String>();
	
	/**
	 * Default Constructor for starting a card game.
	 * 
	 * It creates and shuffles a standard 52 card deck WITHOUT Jokers
	 * 
	 * 
	 */
	public CardGame(String host,String gameName)
	{
		

		for (int i = 0; i < 4; i++)
		{

			for (int j = 0; j < 13; j++)
			{
				cards.add(new Card(Card.CardNumber.values()[j], Card.CardSuite
						.values()[i],false));
			}

		}
		Collections.shuffle(cards);
		
		
		HostName = host;
		Name = gameName;
		
		players.add("DECK");
		activePlayers.add("DECK");
		nameMap.put("DECK", "DECK");
		playerCards.put("DECK", new LinkedList<Card>());
		GameStarted = true;
		
	}
	
	
	/**
	 * Default method used to add players to the game.
	 * 
	 * Do initialization logic for adding players here
	 * 
	 * @param pID player identification string
	 * @return true if player was added to the game; false otherwise
	 * @throws Exception 
	 */
	public boolean AddPlayer(String pID,String Name) throws Exception
	{
		for(String p : players)
		{

			if(p != "DECK")
			{
				
			
				
				
				message = new Message.Builder()
				.addData("ResponseType", "NewPlayer")
				.addData("Player", p)
				.addData("Name", nameMap.get(p))
				.build();
				if(p != pID)
				{
					Result result = sender.send(message, pID,5); //Send the new player all the current players
				}
			

			}
		}
		
		if(players.contains(pID))
		{
			return false;
		}
		else
		{
			for(String p : players)
			{
				if(p != "DECK")
				{
				
				message = new Message.Builder()
				.addData("ResponseType", "NewPlayer")
				.addData("Player", pID)
				.addData("Name", Name)
				.build();
				 if(p != pID)
				 {
					 
				 
				  Result result = sender.send(message, p,5); //Send each player the new players Name
				 }
				 
				 }
			}
			
		
			players.add(pID);
			activePlayers.add(pID);
			nameMap.put(pID, Name);
			
			if(pID ==  HostName)
			{
				playerCards.put(pID, new LinkedList<Card>(cards));
				cards.clear();
			}
			else
			{
				playerCards.put(pID, new LinkedList<Card>());
			}
			

			return true;
		}
		

	}

	
	public void PassCard(GameRequest req) throws Exception
	{
		Result result;
		
			if(playerCards.get(req.fromPlayerID).isEmpty())
			{
				message = new Message.Builder()
				.addData("ResponseType", "ERROR")
				.addData("Message", "That player doesn't have any cards")
				.build();
				
				result = sender.send(message, req.requestingPlayerID,5);
				return;
			}
			
			if(req.booleanCondition)
			{
				
				

					for(Card c : playerCards.get(req.fromPlayerID))
					{
						playerCards.get(req.toPlayerID).add(c);
					}
					playerCards.get(req.fromPlayerID).clear();

					message = new Message.Builder()
					.addData("ResponseType", "OK")
					.addData("Player", req.fromPlayerID)
					.addData("toPlayer", req.toPlayerID)
					.addData("Card", null)
					.build();
					
					for(String p : players)
					{
						if(p != "DECK")
						{
							result = sender.send(message, p,5);
						}
					}
				
					
				
					
					
			}
			else
			{
				
				
				
				Card c;
				if(req.cardNumberString == null)
				{
					ArrayList<Card> tempList = new ArrayList<Card>();
					
					while(!playerCards.get(req.fromPlayerID).isEmpty())
					{
						tempList.add(playerCards.get(req.fromPlayerID).poll());
					}
					
					Collections.shuffle(tempList);
					
					for(Card car : tempList)
					{
						
						playerCards.get(req.fromPlayerID).add(car);
					}
					
					c = playerCards.get(req.fromPlayerID).peek();
					
				}
				else
				{
					c = new Card(req.cardNumberString,true);
				}
				
				c.cardShowing = req.isShown;
				
					if(playerCards.get(req.fromPlayerID).contains(c))
					{
						
							
							
							playerCards.get(req.toPlayerID).add(c);
							playerCards.get(req.fromPlayerID).remove(c);
	
						
						
						message = new Message.Builder()
						.addData("ResponseType", "PassCard")
						.addData("Player", req.fromPlayerID)
						.addData("toPlayer", req.toPlayerID)
						.addData("Card", c.toNumberString())
						.addData("isShown",String.valueOf(req.isShown))
						.build();
						
						for(String p : players)
						{
							if(p != "DECK")
							{
								result = sender.send(message, p,5);
							}
						}
						
					}
					else
					{
						message = new Message.Builder()
						.addData("ResponseType", "ERROR")
						.addData("Message", "That player doesn't have that card")
						.build();
						
						result = sender.send(message, req.requestingPlayerID,5);
					}
				
			}
			
			
				
				
		
	
		
	
	}
	
	
	
	/**
	 * 
	 * Default method for handling all GameRequest objects that the SocketManager can't handle itself
	 * 
	 * @param req The GameRequest Object to handle
	 * @throws Exception General throws for any Exceptions that could occur
	 */
	public void HandleRequest(GameRequest req) throws Exception
	{
		Result result;
		
		switch(req.requestID)
		{
							
			case PassCard:

				PassCard(req);	
				
				break;
				
			case SendMessage:
				
				if(req.toPlayerID != null)
				{
					message = new Message.Builder()
					.addData("ResponseType", "OK")
					.addData("Message", req.Message)
					.build();
					
					result = sender.send(message, req.toPlayerID,5);
				}
				else
				{
					message = new Message.Builder()
					.addData("ResponseType", "OK")
					.addData("Message", req.Message)
					.build();
					
					for(String p : players)
					{
						
						
						if(p != req.requestingPlayerID && p != "DECK")
						{
							result = sender.send(message, p,5);
						}
						
						
							
						
					}
				}
				
				
				break;
					
			case LeaveGame:

				for(Card c : playerCards.get(req.requestingPlayerID))
				{
					
					playerCards.get("DECK").add(c);
					
				}
				playerCards.remove(req.requestingPlayerID);			
				players.remove(req.requestingPlayerID);
				activePlayers.remove(req.requestingPlayerID);
				
				message = new Message.Builder()
				.addData("ResponseType", "PlayerLeft")
				.addData("Player", req.requestingPlayerID)
				.build();
				
				for(String pID : players)
				{
					result = sender.send(message, pID,5);
				}
				
				break;	
				
			case GetCards:
				

				if(cardLock.contains(req.toPlayerID))
				{
					
					message = new Message.Builder()
					.addData("ResponseType", "ERROR")
					.addData("Message", "That player is not allowing Card view")
					.build();
					
					result = sender.send(message, req.requestingPlayerID,5);
					
				}
				else
				{
					
					String cards = "";
				//	Queue<Card> list = playerCards.get(req.toPlayerID);
					
					//Card car = playerCards.get(req.toPlayerID).poll();
					
					//if(car != null)
					//{
					//	playerCards.get(req.toPlayerID).add(car);
					//}
					
					for(Card c : playerCards.get(req.toPlayerID))
					{
						
						cards += c.toNumberString() + ":" + c.cardShowing + ";";
					}
					
					message = new Message.Builder()
					.addData("ResponseType", "CardsList")
					.addData("Player", req.toPlayerID)
					.addData("Cards", cards)
					.build();
					
					result = sender.send(message, req.requestingPlayerID,5);
					
					
				}
				
				
				break;
				
				
			case LockCards:
				
				if(req.booleanCondition)
				{
					cardLock.add(req.requestingPlayerID);
				}
				else
				{
					cardLock.remove(req.requestingPlayerID);
				}
				
				break;
				
			case EndGame:
				
				EndGame();
				
				break;
		
	
				
			default:
				
				message = new Message.Builder()
				.addData("ResponseType", "ERROR")
				.addData("Message", "Invalid Request Type")
				.build();
				
				result = sender.send(message, req.requestingPlayerID,5);
				
				
				break;
			
			
			
		}
	}
	
	

	public void EndGame()
	{
		GameFinished = true;
	}

}
